#include "alu.h"

LaneChannelAluSrcSender::LaneChannelAluSrcSender(JObject *parent) :
    LanePortSender(parent),
    addr(new PortOut<int>(this)),
    data0(new PortOut<std::complex<float>>(this)),
    data1(new PortOut<std::complex<float>>(this)),
    op(new PortOut<int>(this))
{
}

void LaneChannelAluSrcSender::connect(LaneChannelAluSrcReceiver *sender)
{
    addr->connect(sender->addr);
    data0->connect(sender->data0);
    data1->connect(sender->data1);
    op->connect(sender->op);
}

void LaneChannelAluSrcSender::put(int data_addr, std::complex<float> data_data0, std::complex<float> data_data1, int data_op)
{
    addr->put(data_addr);
    data0->put(data_data0);
    data1->put(data_data1);
    op->put(data_op);
}

void LaneChannelAluSrcSender::put_bypass(LaneChannelAluSrcReceiver *receiver)
{
    addr->put(receiver->addr->get());
    data0->put(receiver->data0->get());
    data1->put(receiver->data1->get());
    op->put(receiver->op->get());
}

bool LaneChannelAluSrcSender::is_any_full()
{
    return addr->is_full() || data0->is_full() || data1->is_full() || op->is_full();
}

LaneChannelAluSrcReceiver::LaneChannelAluSrcReceiver(JObject *parent) :
    LanePortReceiver(parent),
    addr(new PortIn<int>(this, -1)),
    data0(new PortIn<std::complex<float>>(this, -1)),
    data1(new PortIn<std::complex<float>>(this, -1)),
    op(new PortIn<int>(this, -1))
{
}

LaneChannelAluSrcPack LaneChannelAluSrcReceiver::get()
{
    LaneChannelAluSrcPack tmp_885063864;
    tmp_885063864.addr = addr->get();
    tmp_885063864.data0 = data0->get();
    tmp_885063864.data1 = data1->get();
    tmp_885063864.op = op->get();
    return tmp_885063864;
}

bool LaneChannelAluSrcReceiver::is_any_empty()
{
    return addr->is_empty() || data0->is_empty() || data1->is_empty() || op->is_empty();
}

bool LaneChannelAluSrcReceiver::is_any_full()
{
    return addr->is_full() || data0->is_full() || data1->is_full() || op->is_full();
}

LaneChannelAluDstSender::LaneChannelAluDstSender(JObject *parent) :
    LanePortSender(parent),
    addr(new PortOut<int>(this)),
    data(new PortOut<std::complex<float>>(this))
{
}

void LaneChannelAluDstSender::connect(LaneChannelAluDstReceiver *sender)
{
    addr->connect(sender->addr);
    data->connect(sender->data);
}

void LaneChannelAluDstSender::put(int data_addr, std::complex<float> data_data)
{
    addr->put(data_addr);
    data->put(data_data);
}

void LaneChannelAluDstSender::put_bypass(LaneChannelAluDstReceiver *receiver)
{
    addr->put(receiver->addr->get());
    data->put(receiver->data->get());
}

bool LaneChannelAluDstSender::is_any_full()
{
    return addr->is_full() || data->is_full();
}

LaneChannelAluDstReceiver::LaneChannelAluDstReceiver(JObject *parent) :
    LanePortReceiver(parent),
    addr(new PortIn<int>(this, -1)),
    data(new PortIn<std::complex<float>>(this, -1))
{
}

LaneChannelAluDstPack LaneChannelAluDstReceiver::get()
{
    LaneChannelAluDstPack tmp_885064760;
    tmp_885064760.addr = addr->get();
    tmp_885064760.data = data->get();
    return tmp_885064760;
}

bool LaneChannelAluDstReceiver::is_any_empty()
{
    return addr->is_empty() || data->is_empty();
}

bool LaneChannelAluDstReceiver::is_any_full()
{
    return addr->is_full() || data->is_full();
}

ChannelAluSender::ChannelAluSender(JObject *parent) :
    ChannelPortSender(parent),
     Src(new LaneChannelAluSrcSender(this)),
     Dst(new LaneChannelAluDstReceiver(this))
{
}

ChannelAluReceiver::ChannelAluReceiver(JObject *parent) :
    ChannelPortReceiver(parent),
    Src(new LaneChannelAluSrcReceiver(this)),
    Dst(new LaneChannelAluDstSender(this))
{
}

void ChannelAlu::connect(ChannelAluSender *sender, ChannelAluReceiver *receiver)
{
    sender->Src->connect(receiver->Src);
    receiver->Dst->connect(sender->Dst);
}

NodeAlu::NodeAlu(Node *parent) :
    Node(parent)
{
    port_receiver = new ChannelAluReceiver(this);
    reg_dst_addr = 0;
    reg_src_0 = std::complex<float>(0.0, 0.0);
    reg_src_1 = std::complex<float>(0.0, 0.0);
    reg_dst_data = std::complex<float>(0.0, 0.0);
    reg_op_code = 0;
}

NodeTaskList NodeAlu::tasks() const
{
    NodeTaskList list;
    list.append(static_cast<NodeTask>(&NodeAlu::task_update));
    return list;
}

void NodeAlu::task_update()
{
    if(port_receiver->Src->is_any_empty())
    {
        return;
    }
    LaneChannelAluSrcPack ret_885023072 = port_receiver->Src->get();
    reg_dst_addr = ret_885023072.addr;
    reg_src_0 = ret_885023072.data0;
    reg_src_1 = ret_885023072.data1;
    reg_op_code = ret_885023072.op;
    if((reg_op_code)==(1))
    {
        reg_dst_data = (reg_src_0)+(reg_src_1);
    }
    else
    {
        if((reg_op_code)==(2))
        {
            reg_dst_data = (reg_src_0)-(reg_src_1);
        }
        else
        {
            if((reg_op_code)==(3))
            {
                reg_dst_data = (reg_src_0)*(reg_src_1);
            }
            else
            {
                if((reg_op_code)==(4))
                {
                    reg_dst_data = (reg_src_0)/(reg_src_1);
                }
                else
                {
                    reg_dst_data = 0;
                }
            }
        }
    }
    port_receiver->Dst->put(reg_dst_addr, reg_dst_data);
}